home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 May / may_2001.iso / intercd / root / Multimedia / ^DivX_Article / virtualdub / VirtualDub-source-1_4d / InputFile.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-20  |  24.4 KB  |  890 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2001 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include <process.h>
  19. #include <stdio.h>
  20.  
  21. #include <windows.h>
  22. #include <vfw.h>
  23. #include <commdlg.h>
  24.  
  25. #include "InputFile.h"
  26. #include "AudioSource.h"
  27. #include "VideoSource.h"
  28. #include "Error.h"
  29. #include "AVIStripeSystem.h"
  30. #include "AVIReadHandler.h"
  31.  
  32. #include "gui.h"
  33. #include "oshelper.h"
  34. #include "prefs.h"
  35.  
  36. #include "resource.h"
  37.  
  38. extern HINSTANCE g_hInst;
  39. extern char g_msgBuf[128];
  40. extern const char fileFiltersAppend[];
  41. extern HWND g_hWnd;
  42.  
  43. /////////////////////////////////////////////////////////////////////
  44.  
  45. InputFileOptions::~InputFileOptions() {
  46. }
  47.  
  48. /////////////////////////////////////////////////////////////////////
  49.  
  50. InputFilenameNode::InputFilenameNode(const char *_n) : name(strdup(_n)) {
  51.     if (!name)
  52.         throw MyMemoryError();
  53. }
  54.  
  55. InputFilenameNode::~InputFilenameNode() {
  56.     free((char *)name);
  57. }
  58.  
  59. /////////////////////////////////////////////////////////////////////
  60.  
  61. InputFile::~InputFile() {
  62.     InputFilenameNode *ifn;
  63.  
  64.     while(ifn = listFiles.RemoveTail())
  65.         delete ifn;
  66. }
  67.  
  68. void InputFile::AddFilename(const char *lpszFile) {
  69.     InputFilenameNode *ifn = new InputFilenameNode(lpszFile);
  70.  
  71.     if (ifn)
  72.         listFiles.AddTail(ifn);
  73. }
  74.  
  75. bool InputFile::Append(const char *szFile) {
  76.     return false;
  77. }
  78.  
  79. void InputFile::setOptions(InputFileOptions *) {
  80. }
  81.  
  82. InputFileOptions *InputFile::promptForOptions(HWND) {
  83.     return NULL;
  84. }
  85.  
  86. InputFileOptions *InputFile::createOptions(const char *buf) {
  87.     return NULL;
  88. }
  89.  
  90. void InputFile::InfoDialog(HWND hwndParent) {
  91. }
  92.  
  93. void InputFile::setAutomated(bool) {
  94. }
  95.  
  96. bool InputFile::isOptimizedForRealtime() {
  97.     return false;
  98. }
  99.  
  100. bool InputFile::isStreaming() {
  101.     return false;
  102. }
  103.  
  104. /////////////////////////////////////////////////////////////////////
  105.  
  106. char InputFileAVI::szME[]="AVI Import Filter";
  107.  
  108. InputFileAVI::InputFileAVI(bool) {
  109.     audioSrc = NULL;
  110.     videoSrc = NULL;
  111.  
  112.     stripesys = NULL;
  113.     stripe_files = NULL;
  114.     fAutomated    = false;
  115.  
  116.     fAcceptPartial = false;
  117.     fInternalMJPEG = false;
  118.     fDisableFastIO = false;
  119.     iMJPEGMode = 0;
  120.     fccForceVideo = 0;
  121.     fccForceVideoHandler = 0;
  122.     lForceAudioHz = 0;
  123.  
  124.     pAVIFile = NULL;
  125.  
  126.     fCompatibilityMode = fRedoKeyFlags = false;
  127.  
  128.     fAutoscanSegments = false;
  129. }
  130.  
  131. InputFileAVI::~InputFileAVI() {
  132.  
  133.     delete videoSrc;
  134.     delete audioSrc;
  135.  
  136.     if (stripe_files) {
  137.         int i;
  138.  
  139.         for(i=0; i<stripe_count; i++)
  140.             if (stripe_files[i])
  141.                 stripe_files[i]->Release();
  142.  
  143.         delete stripe_files;
  144.     }
  145.     delete stripesys;
  146.  
  147.     if (pAVIFile)
  148.         pAVIFile->Release();
  149. }
  150.  
  151. ///////////////////////////////////////////////
  152.  
  153.  
  154.  
  155. class InputFileAVIOptions : public InputFileOptions {
  156. public:
  157.     struct InputFileAVIOpts {
  158.         int len;
  159.         int iMJPEGMode;
  160.         FOURCC fccForceVideo;
  161.         FOURCC fccForceVideoHandler;
  162.         long lForceAudioHz;
  163.  
  164.         bool fCompatibilityMode;
  165.         bool fAcceptPartial;
  166.         bool fRedoKeyFlags;
  167.         bool fInternalMJPEG;
  168.         bool fDisableFastIO;
  169.     } opts;
  170.         
  171.     ~InputFileAVIOptions();
  172.  
  173.     bool read(const char *buf);
  174.     int write(char *buf, int buflen);
  175.  
  176.     static BOOL APIENTRY SetupDlgProc( HWND hDlg, UINT message, UINT wParam, LONG lParam);
  177. };
  178.  
  179. InputFileAVIOptions::~InputFileAVIOptions() {
  180. }
  181.  
  182. bool InputFileAVIOptions::read(const char *buf) {
  183.     const InputFileAVIOpts *pp = (const InputFileAVIOpts *)buf;
  184.  
  185.     if (pp->len != sizeof(InputFileAVIOpts))
  186.         return false;
  187.  
  188.     opts = *pp;
  189.  
  190.     return true;
  191. }
  192.  
  193. int InputFileAVIOptions::write(char *buf, int buflen) {
  194.     InputFileAVIOpts *pp = (InputFileAVIOpts *)buf;
  195.  
  196.     if (buflen<sizeof(InputFileAVIOpts))
  197.         return 0;
  198.  
  199.     opts.len = sizeof(InputFileAVIOpts);
  200.     *pp = opts;
  201.  
  202.     return sizeof(InputFileAVIOpts);
  203. }
  204.  
  205. ///////
  206.  
  207. BOOL APIENTRY InputFileAVIOptions::SetupDlgProc( HWND hDlg, UINT message, UINT wParam, LONG lParam) {
  208.     InputFileAVIOptions *thisPtr = (InputFileAVIOptions *)GetWindowLong(hDlg, DWL_USER);
  209.  
  210.     switch(message) {
  211.         case WM_INITDIALOG:
  212.             SetWindowLong(hDlg, DWL_USER, lParam);
  213.             SendDlgItemMessage(hDlg, IDC_FORCE_FOURCC, EM_LIMITTEXT, 4, 0);
  214.             CheckDlgButton(hDlg, IDC_IF_NORMAL, BST_CHECKED);
  215.             return TRUE;
  216.  
  217.         case WM_COMMAND:
  218.             switch(LOWORD(wParam)) {
  219.             case IDCANCEL:
  220.                 if (GetDlgItem(hDlg, IDC_ACCEPTPARTIAL))
  221.                     thisPtr->opts.fAcceptPartial = !!IsDlgButtonChecked(hDlg, IDC_ACCEPTPARTIAL);
  222.  
  223.                 thisPtr->opts.fCompatibilityMode = !!IsDlgButtonChecked(hDlg, IDC_AVI_COMPATIBILITYMODE);
  224.                 thisPtr->opts.fRedoKeyFlags = !!IsDlgButtonChecked(hDlg, IDC_AVI_REKEY);
  225.                 thisPtr->opts.fInternalMJPEG = !!IsDlgButtonChecked(hDlg, IDC_AVI_INTERNALMJPEG);
  226.                 thisPtr->opts.fDisableFastIO = !!IsDlgButtonChecked(hDlg, IDC_AVI_DISABLEOPTIMIZEDIO);
  227.  
  228.                 if (IsDlgButtonChecked(hDlg, IDC_IF_NORMAL))
  229.                     thisPtr->opts.iMJPEGMode = VideoSourceAVI::IFMODE_NORMAL;
  230.                 else if (IsDlgButtonChecked(hDlg, IDC_IF_SWAP))
  231.                     thisPtr->opts.iMJPEGMode = VideoSourceAVI::IFMODE_SWAP;
  232.                 else if (IsDlgButtonChecked(hDlg, IDC_IF_SPLITNOSWAP))
  233.                     thisPtr->opts.iMJPEGMode = VideoSourceAVI::IFMODE_SPLIT1;
  234.                 else if (IsDlgButtonChecked(hDlg, IDC_IF_SPLITSWAP))
  235.                     thisPtr->opts.iMJPEGMode = VideoSourceAVI::IFMODE_SPLIT2;
  236.                 else if (IsDlgButtonChecked(hDlg, IDC_IF_DISCARDFIRST))
  237.                     thisPtr->opts.iMJPEGMode = VideoSourceAVI::IFMODE_DISCARD1;
  238.                 else if (IsDlgButtonChecked(hDlg, IDC_IF_DISCARDSECOND))
  239.                     thisPtr->opts.iMJPEGMode = VideoSourceAVI::IFMODE_DISCARD2;
  240.  
  241.                 if (IsDlgButtonChecked(hDlg, IDC_FORCE_FOURCC)) {
  242.                     union {
  243.                         char c[5];
  244.                         FOURCC fccType;
  245.                     };
  246.                     int i;
  247.  
  248.                     i = SendDlgItemMessage(hDlg, IDC_FOURCC, WM_GETTEXT, sizeof c, (LPARAM)c);
  249.  
  250.                     memset(c+i, ' ', 5-i);
  251.  
  252.                     if (fccType == 0x20202020)
  253.                         fccType = ' BID';        // force nothing to DIB, since 0 means no force
  254.  
  255.                     thisPtr->opts.fccForceVideo = fccType;
  256.                 } else
  257.                     thisPtr->opts.fccForceVideo = 0;
  258.  
  259.                 if (IsDlgButtonChecked(hDlg, IDC_FORCE_HANDLER)) {
  260.                     union {
  261.                         char c[5];
  262.                         FOURCC fccType;
  263.                     };
  264.                     int i;
  265.  
  266.                     i = SendDlgItemMessage(hDlg, IDC_FOURCC2, WM_GETTEXT, sizeof c, (LPARAM)c);
  267.  
  268.                     memset(c+i, ' ', 5-i);
  269.  
  270.                     if (fccType == 0x20202020)
  271.                         fccType = ' BID';        // force nothing to DIB, since 0 means no force
  272.  
  273.                     thisPtr->opts.fccForceVideoHandler = fccType;
  274.                 } else
  275.                     thisPtr->opts.fccForceVideoHandler = 0;
  276.  
  277.                 if (IsDlgButtonChecked(hDlg, IDC_FORCE_SAMPRATE))
  278.                     thisPtr->opts.lForceAudioHz = GetDlgItemInt(hDlg, IDC_AUDIORATE, NULL, FALSE);
  279.                 else
  280.                     thisPtr->opts.lForceAudioHz = 0;
  281.                 
  282.                 EndDialog(hDlg, 0);
  283.                 return TRUE;
  284.  
  285.             case IDC_FORCE_FOURCC:
  286.                 EnableWindow(GetDlgItem(hDlg, IDC_FOURCC), IsDlgButtonChecked(hDlg, IDC_FORCE_FOURCC));
  287.                 return TRUE;
  288.  
  289.             case IDC_FORCE_HANDLER:
  290.                 EnableWindow(GetDlgItem(hDlg, IDC_FOURCC2), IsDlgButtonChecked(hDlg, IDC_FORCE_HANDLER));
  291.                 return TRUE;
  292.  
  293.             case IDC_FORCE_SAMPRATE:
  294.                 EnableWindow(GetDlgItem(hDlg, IDC_AUDIORATE), IsDlgButtonChecked(hDlg, IDC_FORCE_SAMPRATE));
  295.                 return TRUE;
  296.             }
  297.             break;
  298.     }
  299.  
  300.     return FALSE;
  301. }
  302.  
  303. void InputFileAVI::setOptions(InputFileOptions *_ifo) {
  304.     InputFileAVIOptions *ifo = (InputFileAVIOptions *)_ifo;
  305.  
  306.     fCompatibilityMode    = ifo->opts.fCompatibilityMode;
  307.     fAcceptPartial        = ifo->opts.fAcceptPartial;
  308.     fRedoKeyFlags        = ifo->opts.fRedoKeyFlags;
  309.     fInternalMJPEG        = ifo->opts.fInternalMJPEG;
  310.     fDisableFastIO        = ifo->opts.fDisableFastIO;
  311.     iMJPEGMode            = ifo->opts.iMJPEGMode;
  312.     fccForceVideo        = ifo->opts.fccForceVideo;
  313.     fccForceVideoHandler= ifo->opts.fccForceVideoHandler;
  314.     lForceAudioHz        = ifo->opts.lForceAudioHz;
  315. }
  316.  
  317. InputFileOptions *InputFileAVI::createOptions(const char *buf) {
  318.     InputFileAVIOptions *ifo = new InputFileAVIOptions();
  319.  
  320.     if (!ifo) throw MyMemoryError();
  321.  
  322.     if (!ifo->read(buf)) {
  323.         delete ifo;
  324.         return NULL;
  325.     }
  326.  
  327.     return ifo;
  328. }
  329.  
  330. InputFileOptions *InputFileAVI::promptForOptions(HWND hwnd) {
  331.     InputFileAVIOptions *ifo = new InputFileAVIOptions();
  332.  
  333.     if (!ifo) throw MyMemoryError();
  334.  
  335.     DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_EXTOPENOPTS_AVI),
  336.             hwnd, InputFileAVIOptions::SetupDlgProc, (LPARAM)ifo);
  337.  
  338.     return ifo;
  339. }
  340.  
  341. ///////////////////////////////////////////////
  342.  
  343. static bool fileExists(const char *fn) {
  344.     DWORD dwAttrib = GetFileAttributes(fn);
  345.  
  346.     return dwAttrib != -1 && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
  347. }
  348.  
  349. void InputFileAVI::EnableSegmentAutoscan() {
  350.     fAutoscanSegments = true;
  351. }
  352.  
  353. void InputFileAVI::ForceCompatibility() {
  354.     fCompatibilityMode = true;
  355. }
  356.  
  357. void InputFileAVI::setAutomated(bool fAuto) {
  358.     fAutomated = fAuto;
  359. }
  360.  
  361. void InputFileAVI::Init(char *szFile) {
  362.     HRESULT err;
  363.     PAVIFILE paf;
  364.  
  365.     AddFilename(szFile);
  366.  
  367.     if (fCompatibilityMode) {
  368.         if (err = AVIFileOpen(&paf, szFile, OF_READ, NULL))
  369.             throw MyAVIError(szME, err);
  370.  
  371.         if (!(pAVIFile = CreateAVIReadHandler(paf))) {
  372.             AVIFileRelease(paf);
  373.             throw MyMemoryError();
  374.         }
  375.     } else {
  376.         if (!(pAVIFile = CreateAVIReadHandler(szFile)))
  377.             throw MyMemoryError();
  378.     }
  379.  
  380.     if (fDisableFastIO)
  381.         pAVIFile->EnableFastIO(false);
  382.  
  383.     if (!(videoSrc = new VideoSourceAVI(pAVIFile,NULL,NULL,fInternalMJPEG, iMJPEGMode, fccForceVideo, fccForceVideoHandler)))
  384.         throw MyMemoryError();
  385.  
  386.     if (!videoSrc->init())
  387.         throw MyError("%s: problem opening video stream", szME);
  388.  
  389.     if (fRedoKeyFlags)
  390.         ((VideoSourceAVI *)videoSrc)->redoKeyFlags();
  391.     else if (pAVIFile->isIndexFabricated() && !fAutomated && !videoSrc->isKeyframeOnly())
  392.         MessageBox(NULL,
  393.             "Warning: VirtualDub has reconstructed the index for this file, but you have not specified "
  394.             "rekeying in the extended open options dialog.  Seeking in this file may be slow.",
  395.             "AVI Import Filter Warning",
  396.             MB_OK|MB_ICONEXCLAMATION);
  397.  
  398.     if (videoSrc->isType1() && !fAutomated)
  399.         MessageBox(NULL,
  400.             "Warning: Type-1 DV file detected. Type-1 DV files have video and audio combined into one stream, "
  401.             "and VirtualDub currently cannot extract the audio. Only the video stream will be available."
  402.             ,
  403.             "AVI Import Filter Warning",
  404.             MB_OK|MB_ICONEXCLAMATION);
  405.  
  406.  
  407.     audioSrc = new AudioSourceAVI(pAVIFile);
  408.     if (!audioSrc->init()) {
  409.         delete audioSrc;
  410.         audioSrc = NULL;
  411.     } else if (lForceAudioHz) {
  412.         WAVEFORMATEX *pwfex = (WAVEFORMATEX *)audioSrc->getFormat();
  413.  
  414.         pwfex->nAvgBytesPerSec = MulDiv(pwfex->nAvgBytesPerSec, lForceAudioHz, pwfex->nSamplesPerSec);
  415.         pwfex->nSamplesPerSec = lForceAudioHz;
  416.         audioSrc->streamInfo.dwScale = pwfex->nBlockAlign;
  417.         audioSrc->streamInfo.dwRate = pwfex->nAvgBytesPerSec;
  418.     }
  419.  
  420.     if (fAutoscanSegments) {
  421.         char szPath[MAX_PATH], szNameTail[MAX_PATH];
  422.         const char *pszName = SplitPathName(szFile);
  423.         char *s = szNameTail;
  424.  
  425.         strcpy(szNameTail, pszName);
  426.         memcpy(szPath, szFile, pszName-szFile);
  427.         szPath[pszName-szFile]=0;
  428.  
  429.         while(*s)
  430.             ++s;
  431.  
  432.         if (s > szNameTail+7 && !stricmp(s-7, ".00.avi")) {
  433.             int nSegment = 0;
  434.             const char *pszPath;
  435.  
  436.             s -= 7;
  437.             *s=0;
  438.  
  439.             MergePath(szPath, szNameTail);
  440.             s = szPath;
  441.             while(*s)
  442.                 ++s;
  443.  
  444.             try {
  445.                 while(pAVIFile->getSegmentHint(&pszPath)) {
  446.  
  447.                     wsprintf(s, ".%02d.avi", ++nSegment);
  448.  
  449.                     if (!fileExists(szPath)) {
  450.                         if (pszPath && *pszPath) {
  451.                             strcpy(szPath, pszPath);
  452.                             MergePath(szPath, szNameTail);
  453.                             s = szPath;
  454.                             while(*s)
  455.                                 ++s;
  456.                         }
  457.                         wsprintf(s, ".%02d.avi", nSegment);
  458.                     }
  459.  
  460.                     if (!fileExists(szPath)) {
  461.                         OPENFILENAME ofn;
  462.                         char szTitle[MAX_PATH];
  463.  
  464.                         wsprintf(szTitle, "Cannot find file %s.%02d.avi", szNameTail, nSegment);
  465.  
  466.                         ofn.lStructSize            = sizeof(OPENFILENAME);
  467.                         ofn.hwndOwner            = g_hWnd;
  468.                         ofn.lpstrFilter            = fileFiltersAppend;
  469.                         ofn.lpstrCustomFilter    = NULL;
  470.                         ofn.nFilterIndex        = 1;
  471.                         ofn.lpstrFile            = szPath;
  472.                         ofn.nMaxFile            = sizeof szPath;
  473.                         ofn.lpstrFileTitle        = NULL;
  474.                         ofn.lpstrInitialDir        = NULL;
  475.                         ofn.lpstrTitle            = szTitle;
  476.                         ofn.Flags                = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_ENABLESIZING;
  477.                         ofn.lpstrDefExt            = g_prefs.main.fAttachExtension ? "avi" : NULL;
  478.  
  479.                         if (!GetOpenFileName(&ofn))
  480.                             throw MyUserAbortError();
  481.  
  482.                         if (!Append(szPath))
  483.                             break;
  484.  
  485.                         ((char *)SplitPathName(szPath))[0] = 0;
  486.                         MergePath(szPath, szNameTail);
  487.                         s = szPath;
  488.                         while(*s)
  489.                             ++s;
  490.  
  491.                     } else if (!Append(szPath))
  492.                         break;
  493.                 }
  494.             } catch(MyError e) {
  495.                 wsprintf(szPath, "Cannot load video segment %02d", nSegment);
  496.  
  497.                 e.post(NULL, szPath);
  498.             }
  499.         }
  500.     }
  501. }
  502.  
  503. bool InputFileAVI::Append(const char *szFile) {
  504.     if (fCompatibilityMode || stripesys)
  505.         return false;
  506.  
  507.     if (!szFile)
  508.         return true;
  509.  
  510.     if (pAVIFile->AppendFile(szFile)) {
  511.         if (videoSrc)
  512.             ((VideoSourceAVI *)videoSrc)->Reinit();
  513.         if (audioSrc)
  514.             ((AudioSourceAVI *)audioSrc)->Reinit();
  515.  
  516.         AddFilename(szFile);
  517.  
  518.         return true;
  519.     }
  520.  
  521.     return false;
  522. }
  523.  
  524. void InputFileAVI::InitStriped(char *szFile) {
  525.     int i;
  526.     HRESULT err;
  527.     PAVIFILE paf;
  528.     IAVIReadHandler *index_file;
  529.  
  530.     if (!(stripesys = new AVIStripeSystem(szFile)))
  531.         throw MyMemoryError();
  532.  
  533.     stripe_count = stripesys->getStripeCount();
  534.  
  535.     if (!(stripe_files = new IAVIReadHandler *[stripe_count]))
  536.         throw MyMemoryError();
  537.  
  538.     for(i=0; i<stripe_count; i++)
  539.         stripe_files[i]=NULL;
  540.  
  541.     for(i=0; i<stripe_count; i++) {
  542.         AVIStripe *asdef = stripesys->getStripeInfo(i);
  543.  
  544.         // Ordinarily, OF_SHARE_DENY_WRITE would be better, but XingMPEG
  545.         // Encoder requires write access to AVI files... *sigh*
  546.  
  547.         if (err = AVIFileOpen(&paf, asdef->szName, OF_READ | OF_SHARE_DENY_NONE, NULL))
  548.             throw MyAVIError("AVI Striped Import Filter", err);
  549.  
  550.         if (!(stripe_files[i] = CreateAVIReadHandler(paf))) {
  551.             AVIFileRelease(paf);
  552.             throw MyMemoryError();
  553.         }
  554.  
  555.         if (asdef->isIndex())
  556.             index_file = stripe_files[i];
  557.     }
  558.  
  559.     if (!(videoSrc = new VideoSourceAVI(index_file, stripesys, stripe_files, fInternalMJPEG, iMJPEGMode, fccForceVideo)))
  560.         throw MyMemoryError();
  561.  
  562.     if (!videoSrc->init())
  563.         throw MyError("%s: problem opening video stream", szME);
  564.  
  565.     if (fRedoKeyFlags) ((VideoSourceAVI *)videoSrc)->redoKeyFlags();
  566.  
  567.     if (!(audioSrc = new AudioSourceAVI(index_file)))
  568.         throw MyMemoryError();
  569.  
  570.     if (!audioSrc->init()) {
  571.         delete audioSrc;
  572.         audioSrc = NULL;
  573.     }
  574. }
  575.  
  576. bool InputFileAVI::isOptimizedForRealtime() {
  577.     return pAVIFile->isOptimizedForRealtime();
  578. }
  579.  
  580. bool InputFileAVI::isStreaming() {
  581.     return pAVIFile->isStreaming();
  582. }
  583.  
  584. ///////////////////////////////////////////////////////////////////////////
  585.  
  586. typedef struct MyFileInfo {
  587.     InputFileAVI *thisPtr;
  588.  
  589.     volatile HWND hWndAbort;
  590.     UINT statTimer;
  591.     long    lVideoKFrames;
  592.     long    lVideoKMinSize;
  593.     __int64 i64VideoKTotalSize;
  594.     long    lVideoKMaxSize;
  595.     long    lVideoCFrames;
  596.     long    lVideoCMinSize;
  597.     __int64    i64VideoCTotalSize;
  598.     long    lVideoCMaxSize;
  599.  
  600.     long    lAudioFrames;
  601.     long    lAudioMinSize;
  602.     __int64    i64AudioTotalSize;
  603.     long    lAudioMaxSize;
  604.  
  605.     long    lAudioPreload;
  606.  
  607.     bool    bAudioFramesIndeterminate;
  608. } MyFileInfo;
  609.  
  610. void InputFileAVI::_InfoDlgThread(void *pvInfo) {
  611.     MyFileInfo *pInfo = (MyFileInfo *)pvInfo;
  612.     LONG i;
  613.     LONG lActualBytes, lActualSamples;
  614.     VideoSourceAVI *inputVideoAVI = (VideoSourceAVI *)pInfo->thisPtr->videoSrc;
  615.     AudioSourceAVI *inputAudioAVI = (AudioSourceAVI *)pInfo->thisPtr->audioSrc;
  616.  
  617.     pInfo->lVideoCMinSize = 0x7FFFFFFF;
  618.     pInfo->lVideoKMinSize = 0x7FFFFFFF;
  619.  
  620.     for(i=inputVideoAVI->lSampleFirst; i<inputVideoAVI->lSampleLast; ++i) {
  621.         if (inputVideoAVI->isKey(i)) {
  622.             ++pInfo->lVideoKFrames;
  623.  
  624.             if (!inputVideoAVI->read(i, 1, NULL, 0, &lActualBytes, NULL)) {
  625.                 pInfo->i64VideoKTotalSize += lActualBytes;
  626.                 if (lActualBytes < pInfo->lVideoKMinSize) pInfo->lVideoKMinSize = lActualBytes;
  627.                 if (lActualBytes > pInfo->lVideoKMaxSize) pInfo->lVideoKMaxSize = lActualBytes;
  628.             }
  629.         } else {
  630.             ++pInfo->lVideoCFrames;
  631.  
  632.             if (!inputVideoAVI->read(i, 1, NULL, 0, &lActualBytes, NULL)) {
  633.                 pInfo->i64VideoCTotalSize += lActualBytes;
  634.                 if (lActualBytes < pInfo->lVideoCMinSize) pInfo->lVideoCMinSize = lActualBytes;
  635.                 if (lActualBytes > pInfo->lVideoCMaxSize) pInfo->lVideoCMaxSize = lActualBytes;
  636.             }
  637.         }
  638.  
  639.         if (pInfo->hWndAbort) {
  640.             SendMessage(pInfo->hWndAbort, WM_USER+256, 0, 0);
  641.             return;
  642.         }
  643.     }
  644.  
  645.     if (inputAudioAVI) {
  646.         pInfo->lAudioMinSize = 0x7FFFFFFF;
  647.         pInfo->bAudioFramesIndeterminate = false;
  648.  
  649.         i = inputAudioAVI->lSampleFirst;
  650.         while(i < inputAudioAVI->lSampleLast) {
  651.             if (inputAudioAVI->read(i, AVISTREAMREAD_CONVENIENT, NULL, 0, &lActualBytes, &lActualSamples))
  652.                 break;
  653.  
  654.             if (!lActualSamples) {
  655.                 pInfo->bAudioFramesIndeterminate = true;
  656.                 break;
  657.             }
  658.  
  659.             ++pInfo->lAudioFrames;
  660.             i += lActualSamples;
  661.  
  662.             if (inputAudioAVI->streamInfo.dwInitialFrames == pInfo->lAudioFrames)
  663.                 pInfo->lAudioPreload = i - inputAudioAVI->lSampleFirst;
  664.  
  665.             pInfo->i64AudioTotalSize += lActualBytes;
  666.             if (lActualBytes < pInfo->lAudioMinSize) pInfo->lAudioMinSize = lActualBytes;
  667.             if (lActualBytes > pInfo->lAudioMaxSize) pInfo->lAudioMaxSize = lActualBytes;
  668.  
  669.             if (pInfo->hWndAbort) {
  670.                 SendMessage(pInfo->hWndAbort, WM_USER+256, 0, 0);
  671.                 return;
  672.             }
  673.         }
  674.     }
  675.  
  676.     pInfo->hWndAbort = (HWND)1;
  677. }
  678.  
  679. BOOL APIENTRY InputFileAVI::_InfoDlgProc( HWND hDlg, UINT message, UINT wParam, LONG lParam) {
  680.     MyFileInfo *pInfo = (MyFileInfo *)GetWindowLong(hDlg, DWL_USER);
  681.     InputFileAVI *thisPtr;
  682.  
  683.     if (pInfo)
  684.         thisPtr = pInfo->thisPtr;
  685.  
  686.     switch (message)
  687.     {
  688.         case WM_INITDIALOG:
  689.             SetWindowLong(hDlg, DWL_USER, lParam);
  690.             pInfo = (MyFileInfo *)lParam;
  691.             thisPtr = pInfo->thisPtr;
  692.  
  693.             if (thisPtr->videoSrc) {
  694.                 ICINFO icinfo;
  695.                 char *s;
  696.                 HIC hic;
  697.                 const VideoSourceAVI *pvs = (const VideoSourceAVI *)thisPtr->videoSrc;
  698.  
  699.                 sprintf(g_msgBuf, "%dx%d, %.3f fps (%ld ╡s)",
  700.                             thisPtr->videoSrc->getImageFormat()->biWidth,
  701.                             thisPtr->videoSrc->getImageFormat()->biHeight,
  702.                             (float)thisPtr->videoSrc->streamInfo.dwRate / thisPtr->videoSrc->streamInfo.dwScale,
  703.                             MulDiv(thisPtr->videoSrc->streamInfo.dwScale, 1000000L, thisPtr->videoSrc->streamInfo.dwRate));
  704.                 SetDlgItemText(hDlg, IDC_VIDEO_FORMAT, g_msgBuf);
  705.  
  706.                 s = g_msgBuf + sprintf(g_msgBuf, "%ld (", thisPtr->videoSrc->streamInfo.dwLength);
  707.                 ticks_to_str(s, MulDiv(1000L*thisPtr->videoSrc->streamInfo.dwLength, thisPtr->videoSrc->streamInfo.dwScale, thisPtr->videoSrc->streamInfo.dwRate));
  708.                 strcat(s,")");
  709.                 SetDlgItemText(hDlg, IDC_VIDEO_NUMFRAMES, g_msgBuf);
  710.  
  711.                 strcpy(g_msgBuf, "Unknown");
  712.  
  713.                 if (hic = pvs->getDecompressorHandle()) {
  714.                     if (ICGetInfo(hic, &icinfo, sizeof(ICINFO)))
  715.                         g_msgBuf[WideCharToMultiByte(CP_ACP, 0, icinfo.szDescription, -1, g_msgBuf, sizeof(g_msgBuf)-7, NULL, NULL)]=0;
  716.                 } else if (pvs->isUsingInternalMJPEG())
  717.                     strcpy(g_msgBuf, "VirtualDub internal MJPEG");
  718.                 else if (pvs->getImageFormat()->biCompression == '2YUY')
  719.                     strcpy(g_msgBuf, "YUV 4:2:2 (YUY2)");
  720.                 else if (pvs->getImageFormat()->biCompression == '024I')
  721.                     strcpy(g_msgBuf, "YUV 4:2:0 (I420)");
  722.                 else
  723.                     sprintf(g_msgBuf, "Uncompressed RGB%d", pvs->getImageFormat()->biBitCount);
  724.  
  725.                 SetDlgItemText(hDlg, IDC_VIDEO_COMPRESSION, g_msgBuf);
  726.             }
  727.             if (thisPtr->audioSrc) {
  728.                 WAVEFORMATEX *fmt = thisPtr->audioSrc->getWaveFormat();
  729.                 DWORD cbwfxTemp;
  730.                 WAVEFORMATEX *pwfxTemp;
  731.                 HACMSTREAM has;
  732.                 HACMDRIVERID hadid;
  733.                 ACMDRIVERDETAILS add;
  734.                 bool fSuccessful = false;
  735.  
  736.                 sprintf(g_msgBuf, "%ldHz", fmt->nSamplesPerSec);
  737.                 SetDlgItemText(hDlg, IDC_AUDIO_SAMPLINGRATE, g_msgBuf);
  738.  
  739.                 sprintf(g_msgBuf, "%d (%s)", fmt->nChannels, fmt->nChannels>1 ? "Stereo" : "Mono");
  740.                 SetDlgItemText(hDlg, IDC_AUDIO_CHANNELS, g_msgBuf);
  741.  
  742.                 sprintf(g_msgBuf, "%d-bit", fmt->wBitsPerSample);
  743.                 SetDlgItemText(hDlg, IDC_AUDIO_PRECISION, g_msgBuf);
  744.  
  745.                 sprintf(g_msgBuf, "%ld", thisPtr->audioSrc->lSampleLast - thisPtr->audioSrc->lSampleFirst);
  746.                 SetDlgItemText(hDlg, IDC_AUDIO_NUMFRAMES, g_msgBuf);
  747.  
  748.                 ////////// Attempt to detect audio compression //////////
  749.  
  750.                 if (fmt->wFormatTag != WAVE_FORMAT_PCM) {
  751.                     // Retrieve maximum format size.
  752.  
  753.                     acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, (LPVOID)&cbwfxTemp);
  754.  
  755.                     // Fill out a destination wave format (PCM).
  756.  
  757.                     if (pwfxTemp = (WAVEFORMATEX *)allocmem(cbwfxTemp)) {
  758.                         pwfxTemp->wFormatTag    = WAVE_FORMAT_PCM;
  759.  
  760.                         // Ask ACM to fill out the details.
  761.  
  762.                         if (!acmFormatSuggest(NULL, fmt, pwfxTemp, cbwfxTemp, ACM_FORMATSUGGESTF_WFORMATTAG)) {
  763.                             if (!acmStreamOpen(&has, NULL, fmt, pwfxTemp, NULL, NULL, NULL, ACM_STREAMOPENF_NONREALTIME)) {
  764.                                 if (!acmDriverID((HACMOBJ)has, &hadid, 0)) {
  765.                                     memset(&add, 0, sizeof add);
  766.  
  767.                                     add.cbStruct = sizeof add;
  768.  
  769.                                     if (!acmDriverDetails(hadid, &add, 0)) {
  770.                                         SetDlgItemText(hDlg, IDC_AUDIO_COMPRESSION, add.szLongName);
  771.  
  772.                                         fSuccessful = true;
  773.                                     }
  774.                                 }
  775.  
  776.                                 acmStreamClose(has, 0);
  777.                             }
  778.                         }
  779.  
  780.                         freemem(pwfxTemp);
  781.                     }
  782.  
  783.                     if (!fSuccessful) {
  784.                         char buf[32];
  785.  
  786.                         wsprintf(buf, "Unknown (tag %04X)", fmt->wFormatTag);
  787.                         SetDlgItemText(hDlg, IDC_AUDIO_COMPRESSION, buf);
  788.                     }
  789.                 } else {
  790.                     // It's a PCM format...
  791.  
  792.                     SetDlgItemText(hDlg, IDC_AUDIO_COMPRESSION, "PCM (Uncompressed)");
  793.                 }
  794.             }
  795.  
  796.             _beginthread(_InfoDlgThread, 10000, pInfo);
  797.  
  798.             pInfo->statTimer = SetTimer(hDlg, 1, 250, NULL);
  799.  
  800.             return (TRUE);
  801.  
  802.         case WM_COMMAND:                      
  803.             if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 
  804.             {
  805.                 if (pInfo->hWndAbort == (HWND)1)
  806.                     EndDialog(hDlg, TRUE);
  807.                 else
  808.                     pInfo->hWndAbort = hDlg;
  809.                 return TRUE;
  810.             }
  811.             break;
  812.  
  813.         case WM_DESTROY:
  814.             if (pInfo->statTimer) KillTimer(hDlg, pInfo->statTimer);
  815.             break;
  816.  
  817.         case WM_TIMER:
  818.             _RPT0(0,"timer hit\n");
  819.             sprintf(g_msgBuf, "%ld", pInfo->lVideoKFrames);
  820.             SetDlgItemText(hDlg, IDC_VIDEO_NUMKEYFRAMES, g_msgBuf);
  821.  
  822.             if (pInfo->lVideoKFrames)
  823.                 sprintf(g_msgBuf, "%ld/%I64d/%ld (%I64dK)"
  824.                             ,pInfo->lVideoKMinSize
  825.                             ,pInfo->i64VideoKTotalSize/pInfo->lVideoKFrames
  826.                             ,pInfo->lVideoKMaxSize
  827.                             ,(pInfo->i64VideoKTotalSize+1023)>>10);
  828.             else
  829.                 strcpy(g_msgBuf,"(no key frames)");
  830.             SetDlgItemText(hDlg, IDC_VIDEO_KEYFRAMESIZES, g_msgBuf);
  831.  
  832.             if (pInfo->lVideoCFrames)
  833.                 sprintf(g_msgBuf, "%ld/%I64d/%ld (%I64dK)"
  834.                             ,pInfo->lVideoCMinSize
  835.                             ,pInfo->i64VideoCTotalSize/pInfo->lVideoCFrames
  836.                             ,pInfo->lVideoCMaxSize
  837.                             ,(pInfo->i64VideoCTotalSize+1023)>>10);
  838.             else
  839.                 strcpy(g_msgBuf,"(no delta frames)");
  840.             SetDlgItemText(hDlg, IDC_VIDEO_NONKEYFRAMESIZES, g_msgBuf);
  841.  
  842.             if (thisPtr->audioSrc) {
  843.                 if (pInfo->bAudioFramesIndeterminate) {
  844.                     SetDlgItemText(hDlg, IDC_AUDIO_NUMFRAMES, "(indeterminate)");
  845.                     SetDlgItemText(hDlg, IDC_AUDIO_FRAMESIZES, "(indeterminate)");
  846.                     SetDlgItemText(hDlg, IDC_AUDIO_PRELOAD, "(indeterminate)");
  847.                 } else {
  848.                     sprintf(g_msgBuf,"%ld",pInfo->lAudioFrames);
  849.                     SetDlgItemText(hDlg, IDC_AUDIO_NUMFRAMES, g_msgBuf);
  850.  
  851.                     if (pInfo->lAudioFrames)
  852.                         sprintf(g_msgBuf, "%ld/%I64d/%ld (%I64dK)"
  853.                                 ,pInfo->lAudioMinSize
  854.                                 ,pInfo->i64AudioTotalSize/pInfo->lAudioFrames
  855.                                 ,pInfo->lAudioMaxSize
  856.                                 ,(pInfo->i64AudioTotalSize+1023)>>10);
  857.                     else
  858.                         strcpy(g_msgBuf,"(no audio frames)");
  859.                     SetDlgItemText(hDlg, IDC_AUDIO_FRAMESIZES, g_msgBuf);
  860.  
  861.                     sprintf(g_msgBuf, "%ld samples (%.2fs)",pInfo->lAudioPreload,(double)pInfo->lAudioPreload/thisPtr->audioSrc->getWaveFormat()->nSamplesPerSec);
  862.                     SetDlgItemText(hDlg, IDC_AUDIO_PRELOAD, g_msgBuf);
  863.                 }
  864.             }
  865.  
  866.             /////////
  867.  
  868.             if (pInfo->hWndAbort) {
  869.                 KillTimer(hDlg, pInfo->statTimer);
  870.                 return TRUE;
  871.             }
  872.  
  873.             break;
  874.  
  875.         case WM_USER+256:
  876.             EndDialog(hDlg, TRUE);  
  877.             break;
  878.     }
  879.     return FALSE;
  880. }
  881.  
  882. void InputFileAVI::InfoDialog(HWND hwndParent) {
  883.     MyFileInfo mai;
  884.  
  885.     memset(&mai, 0, sizeof mai);
  886.     mai.thisPtr = this;
  887.  
  888.     DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_AVI_INFO), hwndParent, _InfoDlgProc, (LPARAM)&mai);
  889. }
  890.